﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Xml.Linq;

namespace Wombat.Core.Services
{
    public class ConfigurationService : IConfigurationService, IConfigurationServiceLoader
    {
        private IDictionary<string, IConfigurationItem> _globalConfigs;
        private IDictionary<string, IDictionary<string, IConfigurationItem>> _typeConfigs;
        private static class Elements
        {
            public static readonly XName GateConfigurations = XName.Get("Gate.Configurations");
            public static readonly XName KeyValuePair = XName.Get("KeyValuePair");
            public static readonly XName ForType = XName.Get("ForType");
        }
        private static class Attributes
        {
            public static readonly XName Name = XName.Get("Name");
            public static readonly XName Key = XName.Get("Key");
            public static readonly XName Value = XName.Get("Value");
        }

        public IDictionary<string, IConfigurationItem> ReadConfigurations()
        {
            return _globalConfigs;
        }

        public IDictionary<string, IConfigurationItem> ReadConfigurations(Type configurableObjectType)
        {
            return _typeConfigs[configurableObjectType.FullName];
        }

        async Task IConfigurationServiceLoader.LoadConfigurationAsync(string configFile)
        {
            var doc = await Task.Factory.StartNew(() => XDocument.Load(configFile));
            await Task.Factory.StartNew(() =>
                                            {
                                                var xElement = doc.Element(Elements.GateConfigurations);
                                                if (xElement != null)
                                                    _globalConfigs = LoadKeyValuePairs(xElement);
                                                else
                                                {
                                                    throw new InvalidOperationException(
                                                        "Error in configuration. Tag 'Gate.Configurations' not found.");
                                                }
                                                _typeConfigs = xElement.Elements(Elements.ForType)
                                                                       .ToDictionary(
                                                                           l => (string) l.Attribute(Attributes.Name),
                                                                           LoadKeyValuePairs);
                                            });
        }

        private static IDictionary<string, IConfigurationItem> LoadKeyValuePairs(XElement xElement)
        {
            return xElement
                .Elements(Elements.KeyValuePair)
                .ToDictionary(l => (string)l.Attribute(Attributes.Key),
                              l => (IConfigurationItem)new StringConfigurationItem { Value = (string)l.Attribute(Attributes.Value) });
        }
    }
}